/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

using System.ComponentModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace QuantConnect.Orders.Serialization
{
    /// <summary>
    /// Data transfer object used for serializing an <see cref="OrderEvent"/> that was just generated by an algorithm
    /// </summary>
    public class SerializedOrderEvent
    {
        /// <summary>
        /// The unique order event id
        /// </summary>
        [JsonProperty("id")]
        public virtual string Id => $"{AlgorithmId}-{OrderId}-{OrderEventId}";

        /// <summary>
        /// Algorithm Id, BacktestId or DeployId
        /// </summary>
        [JsonProperty("algorithmId")]
        public string AlgorithmId { get; set; }

        /// <summary>
        /// Id of the order this event comes from.
        /// </summary>
        [JsonProperty("orderId")]
        public int OrderId { get; set; }

        /// <summary>
        /// The unique order event id for each order
        /// </summary>
        [JsonProperty("orderEventId")]
        public int OrderEventId { get; set; }

        /// <summary>
        /// Easy access to the order symbol associated with this event.
        /// </summary>
        [JsonProperty("symbol")]
        public string Symbol { get; set; }

        /// <summary>
        /// The mapped symbol value
        /// </summary>
        [JsonProperty(PropertyName = "symbolValue")]
        public string SymbolValue { get; set; }

        /// <summary>
        /// The symbols permanent ticker. For equities, by convention this is the first ticker symbol for which the security traded
        /// </summary>
        [JsonProperty(PropertyName = "symbolPermtick")]
        public string SymbolPermtick { get; set; }

        /// <summary>
        /// The time of this event in unix timestamp
        /// </summary>
        [JsonProperty("time")]
        public double Time { get; set; }

        /// <summary>
        /// Status message of the order.
        /// </summary>
        [JsonProperty("status"), JsonConverter(typeof(StringEnumConverter), true)]
        public OrderStatus Status { get; set; }

        /// <summary>
        /// The fee amount associated with the order
        /// </summary>
        [JsonProperty("orderFeeAmount", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public decimal? OrderFeeAmount { get; set; }

        /// <summary>
        /// The fee currency associated with the order
        /// </summary>
        [JsonProperty("orderFeeCurrency", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public string OrderFeeCurrency { get; set; }

        /// <summary>
        /// Fill price information about the order
        /// </summary>
        [JsonProperty("fillPrice")]
        public decimal FillPrice { get; set; }

        /// <summary>
        /// Currency for the fill price
        /// </summary>
        [JsonProperty("fillPriceCurrency")]
        public string FillPriceCurrency { get; set; }

        /// <summary>
        /// Number of shares of the order that was filled in this event.
        /// </summary>
        [JsonProperty("fillQuantity")]
        public decimal FillQuantity { get; set; }

        /// <summary>
        /// Order direction.
        /// </summary>
        [JsonProperty("direction"), JsonConverter(typeof(StringEnumConverter), true)]
        public OrderDirection Direction { get; set; }

        /// <summary>
        /// Any message from the exchange.
        /// </summary>
        [DefaultValue(""), JsonProperty("message", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public string Message { get; set; }

        /// <summary>
        /// True if the order event is an assignment
        /// </summary>
        [JsonProperty("isAssignment")]
        public bool IsAssignment { get; set; }

        /// <summary>
        /// The current order quantity
        /// </summary>
        [JsonProperty("quantity")]
        public decimal Quantity { get; set; }

        /// <summary>
        /// The current stop price
        /// </summary>
        [JsonProperty("stopPrice", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public decimal? StopPrice { get; set; }

        /// <summary>
        /// The current limit price
        /// </summary>
        [JsonProperty("limitPrice", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public decimal? LimitPrice { get; set; }

        /// <summary>
        /// True if the order event's option is In-The-Money (ITM)
        /// </summary>
        [JsonProperty("isInTheMoney", DefaultValueHandling = DefaultValueHandling.Ignore)]
        public bool IsInTheMoney { get; set; }

        /// <summary>
        /// Empty constructor required for JSON converter.
        /// </summary>
        public SerializedOrderEvent()
        {
        }

        /// <summary>
        /// Creates a new instances based on the provided order event and algorithm Id
        /// </summary>
        public SerializedOrderEvent(OrderEvent orderEvent, string algorithmId)
        {
            AlgorithmId = algorithmId;
            OrderId = orderEvent.OrderId;
            OrderEventId = orderEvent.Id;
            Symbol = orderEvent.Symbol.ID.ToString();
            SymbolValue = orderEvent.Symbol.Value;
            SymbolPermtick = orderEvent.Symbol.ID.Symbol;
            Time = QuantConnect.Time.DateTimeToUnixTimeStamp(orderEvent.UtcTime);
            Status = orderEvent.Status;
            if (orderEvent.OrderFee.Value.Currency != Currencies.NullCurrency)
            {
                OrderFeeAmount = orderEvent.OrderFee.Value.Amount;
                OrderFeeCurrency = orderEvent.OrderFee.Value.Currency;
            }
            FillPrice = orderEvent.FillPrice;
            FillPriceCurrency = orderEvent.FillPriceCurrency;
            FillQuantity = orderEvent.FillQuantity;
            Direction = orderEvent.Direction;
            Message = orderEvent.Message;
            IsAssignment = orderEvent.IsAssignment;
            IsInTheMoney = orderEvent.IsInTheMoney;
            Quantity = orderEvent.Quantity;
            StopPrice = orderEvent.StopPrice;
            LimitPrice = orderEvent.LimitPrice;
        }

        #region BackwardsCompatibility

        [JsonProperty("algorithm-id")]
        string OldAlgorithmId
        {
            set
            {
                AlgorithmId = value;
            }
        }
        [JsonProperty("order-id")]
        int OldOrderId
        {
            set
            {
                OrderId = value;
            }
        }
        [JsonProperty("order-event-id")]
        int OldOrderEventId
        {
            set
            {
                OrderEventId = value;
            }
        }
        [JsonProperty(PropertyName = "symbol-value")]
        string OldSymbolValue
        {
            set
            {
                SymbolValue = value;
            }
        }
        [JsonProperty(PropertyName = "symbol-permtick")]
        string OldSymbolPermtick
        {
            set
            {
                SymbolPermtick = value;
            }
        }
        [JsonProperty("order-fee-amount", DefaultValueHandling = DefaultValueHandling.Ignore)]
        decimal? OldOrderFeeAmount
        {
            set
            {
                OrderFeeAmount = value;
            }
        }
        [JsonProperty("order-fee-currency", DefaultValueHandling = DefaultValueHandling.Ignore)]
        string OldOrderFeeCurrency
        {
            set
            {
                OrderFeeCurrency = value;
            }
        }
        [JsonProperty("fill-price")]
        decimal OldFillPrice
        {
            set
            {
                FillPrice = value;
            }
        }
        [JsonProperty("fill-price-currency")]
        string OldFillPriceCurrency
        {
            set
            {
                FillPriceCurrency = value;
            }
        }
        [JsonProperty("fill-quantity")]
        decimal OldFillQuantity
        {
            set
            {
                FillQuantity = value;
            }
        }
        [JsonProperty("is-assignment")]
        bool OldIsAssignment
        {
            set
            {
                IsAssignment = value;
            }
        }
        [JsonProperty("stop-price", DefaultValueHandling = DefaultValueHandling.Ignore)]
        decimal? OldStopPrice
        {
            set
            {
                StopPrice = value;
            }
        }
        [JsonProperty("limit-price", DefaultValueHandling = DefaultValueHandling.Ignore)]
        decimal? OldLimitPrice
        {
            set
            {
                LimitPrice = value;
            }
        }
        [JsonProperty("is-in-the-money", DefaultValueHandling = DefaultValueHandling.Ignore)]
        bool OldIsInTheMoney
        {
            set
            {
                IsInTheMoney = value;
            }
        }
        #endregion
    }
}
